package com.cloud.control.service.utils;

import javax.crypto.Cipher;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.HashMap;

import javax.crypto.Cipher;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;



/**
 * modulus: 126299031190264152032243998313136498657812878958149970866336104549887208915300657679380575718385991696325376510747943063980294082050004746008998778964525314590493345902456577173476091190305989160649736397918130970422844669578056345961431809600009038151452794912407135370236035954244927660382536246468914275857
   public_exponent: 
                      65537
   private_exponent: 
      66601988463547753089618880658284593338328167245886491495499882100860612174997188296678100871681948716374033175327660898288889687896122251889329658071226850387336424508711979463653383549505734185068757887221897702888890497545673173898297965665114056830901795522418036152430035046516270016829264939509537738753
     加密后的密文:  
      49C617F37D649FD09C8FC9B65BA3072EB3337087DDF5A1372359B5EFD48D3A215CB9F24FDC268596ADF87C080AE5FE440ED15313FA0D52D3B5B010958ABBFC14FE163F7A7DD34DD08CA73FFFFB77E0DF12F0BDF153B3A6A840BE98106488B3976BB9A574B2C02F50D5538D2ED63EFDD2049D5377C56D695EBB38667CA50993CF
   128

    解密后的明文:   123456789
 * @author Administrator
 *
 */
public class RSAUtils {
	private static final Log log = LogFactory.getLog(RSAUtils.class);
	
       /*这组密码为加密存储user到客户端使用*/
		private static final String modulus="126299031190264152032243998313136498657812878958149970866336104549887208915300657679380575718385991696325376510747943063980294082050004746008998778964525314590493345902456577173476091190305989160649736397918130970422844669578056345961431809600009038151452794912407135370236035954244927660382536246468914275857";
		private static final String public_exponent="65537";
		private static final String private_exponent="66601988463547753089618880658284593338328167245886491495499882100860612174997188296678100871681948716374033175327660898288889687896122251889329658071226850387336424508711979463653383549505734185068757887221897702888890497545673173898297965665114056830901795522418036152430035046516270016829264939509537738753";
        /*这组密码为加密存储user到数据库使用*/
		private static final String modulusDB="117387361390832452824646278500956099173509021954290696026172002506548393857782073537141289820850067628904859541860438716395209380093421198316685559118392813544442067530154712840987883785135272169789817455912700602631979815289167401205095763190184399322290607564891516903170582762551597668804040175208863621563";
		private static final String public_exponentDB="65537";
		private static final String private_exponentDB="36983905854676114041278916619432405141135759728278595168353746856816931449036181918532940968016726374439286812340118385280502361721912216043500975398272340261121760106366623757698167161445513783126676794266062463158062716106491877572838234877320183361187721498954761902320972051054025491964646395316680553025";

		public static void main(String[] args) throws Exception {
/**
			HashMap<String, Object> map = RSAUtils.getKeys();
			//生成公钥和私钥
			RSAPublicKey publicKey = (RSAPublicKey) map.get("public");
			RSAPrivateKey privateKey = (RSAPrivateKey) map.get("private");
			
			//模
			String modulus = publicKey.getModulus().toString();
			System.out.println("modulus: "+modulus);
			//公钥指数
			String public_exponent = publicKey.getPublicExponent().toString();
			System.out.println("public_exponent: "+public_exponent);
			//私钥指数
			String private_exponent = privateKey.getPrivateExponent().toString();
			System.out.println("private_exponent: "+private_exponent);
			//明文
			String ming = "123456789";
			//使用模和指数生成公钥和私钥
			//modulus="126299031190264152032243998313136498657812878958149970866336104549887208915300657679380575718385991696325376510747943063980294082050004746008998778964525314590493345902456577173476091190305989160649736397918130970422844669578056345961431809600009038151452794912407135370236035954244927660382536246468914275857";
			//public_exponent="65537";
			//private_exponent="66601988463547753089618880658284593338328167245886491495499882100860612174997188296678100871681948716374033175327660898288889687896122251889329658071226850387336424508711979463653383549505734185068757887221897702888890497545673173898297965665114056830901795522418036152430035046516270016829264939509537738753";
				
			RSAPublicKey pubKey = RSAUtils.getPublicKey(modulusDB, public_exponentDB);
			//加密后的密文
			String mi = RSAUtils.encryptByPublicKey(ming, pubKey);
			System.err.println("加密后的密文:  \r\n"+mi);
			//解密后的明文
			RSAPrivateKey priKey = RSAUtils.getPrivateKey(modulusDB, private_exponentDB);
			ming = RSAUtils.decryptByPrivateKey(mi, priKey);
			System.err.println("解密后的明文:  \r\n"+ming);
**/		
			String user="stjack";
			String db=encryptRSADB(user);
			System.out.println("\r\n\r\n数据库加密用户: \r\n\r\n"+db);
			String client=encryptRSA(user);
			System.out.println("\r\n\r\n客户端加密用户: \r\n\r\n"+client);


			System.out.println("数据库和客户端的对比结果："+compareEncryptedUser(client,db));
			
			//System.out.println("Encryption compare: "+compareEncryptedUser(client,db));
		}
    
	/**
	 * 比较数据库存储的加密用户和客户端发送的数字证书的value是否一致,验证用户是合法的用户!
	 * @param in
	 * @return
	 */
	public static  boolean compareEncryptedUser(String in,String inDB){
		boolean flag=false;
		try {
			String userFromClient=decryptRSA(in);
			//System.out.println("userFromClient: \r\n\r\n"+userFromClient);
			String userFromDB=decryptRSADB(inDB);
			//System.out.println("userFromDB: \r\n\r\n"+userFromDB);
			if(userFromClient.equalsIgnoreCase(userFromDB)){
				return true;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return flag;
	}
	/**
	 * 采用内置的key进行RSA加密!
	 * @param input
	 * @return
	 * @throws Exception 
	 */
	public static String encryptRSA(String input){
		String output=null;
		try {
			RSAPublicKey pubKey = RSAUtils.getPublicKey(modulus, public_exponent);
			
			output=encryptByPublicKey(input, pubKey);
		} catch (Exception e) {
			return null;
		}
		return output;
	}
	/**
	 * 采用内置的key进行RSA解密!
	 * @param input
	 * @return
	 * @throws Exception 
	 */
	public static String decryptRSA(String input){
		String output=null;
		try {
			RSAPrivateKey priKey = getPrivateKey(modulus, private_exponent);
			output=decryptByPrivateKey(input, priKey);
		} catch (Exception e) {
			return null;
		}
		return output;
	}

	/*存入数据库的user解密*/
	public static String decryptRSADB(String input){
		RSAPrivateKey priKey = getPrivateKey(modulusDB, private_exponentDB);
		String output;
		try {
			output = decryptByPrivateKey(input, priKey);
		} catch (Exception e) {
			log.error("decryption failed");
			return null;
		}
		return output;
	}
	/*存入数据库的user加密*/
	public static String encryptRSADB(String input) throws Exception{
		RSAPublicKey pubKey = RSAUtils.getPublicKey(modulusDB, public_exponentDB);
		
		String output=encryptByPublicKey(input, pubKey);
		return output;
	}
	
	//该代码片段来自于: http://www.sharejs.com/codes/java/6652    }

	/**
	 * 生成公钥和私钥
	 * @throws NoSuchAlgorithmException 
	 *
	 */
	public static HashMap<String, Object> getKeys() throws NoSuchAlgorithmException{
		HashMap<String, Object> map = new HashMap<String, Object>();
		KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        keyPairGen.initialize(1024);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        map.put("public", publicKey);
        map.put("private", privateKey);
        return map;
	}
	/**
	 * 使用模和指数生成RSA公钥
	 * 注意：【此代码用了默认补位方式，为RSA/None/PKCS1Padding，不同JDK默认的补位方式可能不同，如Android默认是RSA
	 * /None/NoPadding】
	 * 
	 * @param modulus
	 *            模
	 * @param exponent
	 *            指数
	 * @return
	 */
	public static RSAPublicKey getPublicKey(String modulus, String exponent) {
		try {
			BigInteger b1 = new BigInteger(modulus);
			BigInteger b2 = new BigInteger(exponent);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
			return (RSAPublicKey) keyFactory.generatePublic(keySpec);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 使用模和指数生成RSA私钥
	 * 注意：【此代码用了默认补位方式，为RSA/None/PKCS1Padding，不同JDK默认的补位方式可能不同，如Android默认是RSA
	 * /None/NoPadding】
	 * 
	 * @param modulus
	 *            模
	 * @param exponent
	 *            指数
	 * @return
	 */
	public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {
		try {
			BigInteger b1 = new BigInteger(modulus);
			BigInteger b2 = new BigInteger(exponent);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
			return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 公钥加密
	 * 
	 * @param data
	 * @param publicKey
	 * @return
	 * @throws Exception
	 */
	public static String encryptByPublicKey(String data, RSAPublicKey publicKey)
			throws Exception {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		// 模长
		int key_len = publicKey.getModulus().bitLength() / 8;
		// 加密数据长度 <= 模长-11
		String[] datas = splitString(data, key_len - 11);
		String mi = "";
		//如果明文长度大于模长-11则要分组加密
		for (String s : datas) {
			mi += bcd2Str(cipher.doFinal(s.getBytes()));
		}
		return mi;
	}

	/**
	 * 私钥解密
	 * 
	 * @param data
	 * @param privateKey
	 * @return
	 * @throws Exception
	 */
	public static String decryptByPrivateKey(String data, RSAPrivateKey privateKey)
			throws Exception {
		Cipher cipher = Cipher.getInstance("RSA");
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		//模长
		int key_len = privateKey.getModulus().bitLength() / 8;
		byte[] bytes = data.getBytes();
		byte[] bcd = ASCII_To_BCD(bytes, bytes.length);
		//System.err.println(bcd.length);
		//如果密文长度大于模长则要分组解密
		String ming = "";
		byte[][] arrays = splitArray(bcd, key_len);
		for(byte[] arr : arrays){
			ming += new String(cipher.doFinal(arr));
		}
		return ming;
	}
	/**
	 * ASCII码转BCD码
	 * 
	 */
	public static byte[] ASCII_To_BCD(byte[] ascii, int asc_len) {
		byte[] bcd = new byte[asc_len / 2];
		int j = 0;
		for (int i = 0; i < (asc_len + 1) / 2; i++) {
			bcd[i] = asc_to_bcd(ascii[j++]);
			bcd[i] = (byte) (((j >= asc_len) ? 0x00 : asc_to_bcd(ascii[j++])) + (bcd[i] << 4));
		}
		return bcd;
	}
	public static byte asc_to_bcd(byte asc) {
		byte bcd;

		if ((asc >= '0') && (asc <= '9'))
			bcd = (byte) (asc - '0');
		else if ((asc >= 'A') && (asc <= 'F'))
			bcd = (byte) (asc - 'A' + 10);
		else if ((asc >= 'a') && (asc <= 'f'))
			bcd = (byte) (asc - 'a' + 10);
		else
			bcd = (byte) (asc - 48);
		return bcd;
	}
	/**
	 * BCD转字符串
	 */
	public static String bcd2Str(byte[] bytes) {
		char temp[] = new char[bytes.length * 2], val;

		for (int i = 0; i < bytes.length; i++) {
			val = (char) (((bytes[i] & 0xf0) >> 4) & 0x0f);
			temp[i * 2] = (char) (val > 9 ? val + 'A' - 10 : val + '0');

			val = (char) (bytes[i] & 0x0f);
			temp[i * 2 + 1] = (char) (val > 9 ? val + 'A' - 10 : val + '0');
		}
		return new String(temp);
	}
	/**
	 * 拆分字符串
	 */
	public static String[] splitString(String string, int len) {
		int x = string.length() / len;
		int y = string.length() % len;
		int z = 0;
		if (y != 0) {
			z = 1;
		}
		String[] strings = new String[x + z];
		String str = "";
		for (int i=0; i<x+z; i++) {
			if (i==x+z-1 && y!=0) {
				str = string.substring(i*len, i*len+y);
			}else{
				str = string.substring(i*len, i*len+len);
			}
			strings[i] = str;
		}
		return strings;
	}
	/**
	 *拆分数组 
	 */
	public static byte[][] splitArray(byte[] data,int len){
		int x = data.length / len;
		int y = data.length % len;
		int z = 0;
		if(y!=0){
			z = 1;
		}
		byte[][] arrays = new byte[x+z][];
		byte[] arr;
		for(int i=0; i<x+z; i++){
			arr = new byte[len];
			if(i==x+z-1 && y!=0){
				System.arraycopy(data, i*len, arr, 0, y);
			}else{
				System.arraycopy(data, i*len, arr, 0, len);
			}
			arrays[i] = arr;
		}
		return arrays;
	}
}

//该代码片段来自于: http://www.sharejs.com/codes/java/6652